package com.zhl.framework.core.common;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.util.concurrent.EventExecutorGroup;

import java.util.List;

import static com.zhl.framework.core.common.constants.RpcConstants.MAGIC_NUMBER;

/**
 * @Author: ZhangLu In DLUT
 * @since: 1.0.0
 * @Description: RPC解码器, 将传输的 ByteBuf 转换成约定的对象，从而进行后续的处理
 */
public class RpcDecoder extends ByteToMessageDecoder {
    /**
     * 协议开头部分的标准长度，2表示2字节的魔数，4表示4字节的长度（int类型的，最大可传输 2^32 个字节的数组）
     */
    public static final int BASE_LENGTH = 2 + 4;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> out) throws Exception {
        // 确保有数据可以读出
        if (byteBuf.readableBytes() > BASE_LENGTH) {
            // 防止收到一些体积过大的数据包 目前限制在1000大小，后期版本这里是可配置模式
            if (byteBuf.readableBytes() > 1000) {
                // 直接略过可读的数据，数据包太大了
                byteBuf.skipBytes(byteBuf.readableBytes());
            }
            // 验证魔数
            // 获取读指针的索引
            int beginReader = byteBuf.readerIndex();
            // 标记读指针 TODO 有啥用这里
            byteBuf.markReaderIndex();
            // 判断魔数
            if (byteBuf.readShort() != MAGIC_NUMBER) {
                // 不是魔数开头，则说明是非法客户端发来的数据包
                ctx.close();
                return;
            }
            // 读取字节数组的长度
            int length = byteBuf.readInt();
            // 判断读取的数据是否完成
            if (byteBuf.readableBytes() < length) {
                // 说明剩余的数据包不是完整的，这里需要重置下读索引
                byteBuf.readerIndex(beginReader);
                return;
            }
            byte[] data = new byte[length];
            byteBuf.readBytes(data);
            // 将字节数组序列化成协议对象 RpcProtocol
            RpcProtocol rpcProtocol = new RpcProtocol(data);
            out.add(rpcProtocol);

        }
    }
}
